home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / pine3.07 / pico / attach.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-30  |  20.4 KB  |  843 lines

  1. /*
  2.  * Program:    Routines to support attachments in the Pine composer 
  3.  *
  4.  * Author:    Michael Seibel
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: mikes@cac.washington.edu
  11.  *
  12.  * Date:    31 Mar 1992
  13.  * Last Edited:    
  14.  *
  15.  * Copyright 1991 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  *
  35.  *
  36.  * NOTES:
  37.  *
  38.  *
  39.  */
  40. #include <stdio.h>
  41. #include <ctype.h>
  42. #include <math.h>
  43. #include "osdep.h"
  44. #include "estruct.h"
  45. #include "edef.h"
  46. #include "pico.h"
  47.  
  48. #ifdef    ATTACHMENTS
  49.  
  50. /*
  51.  * external declarations
  52.  */
  53. extern struct headerentry headents[];
  54. extern char   *gethomedir();
  55.  
  56. /*
  57.  * other useful declarations
  58.  */
  59. struct hdr_line  *next_line(), *prev_line();
  60. PATMT  *NewAttach();
  61. char   *prettysz();
  62. void   ZotAttach();
  63.  
  64.  
  65. /* 
  66.  * max number of attachments
  67.  */
  68. #define    MAXATCH    64
  69.  
  70.  
  71. /*
  72.  * AskAttach - ask for attachment fields and build resulting structure
  73.  *             return pointer to that struct if OK, NULL otherwise
  74.  */
  75. AskAttach(fn, sz, cmnt)
  76. char *fn, *sz, *cmnt;
  77. {
  78.     int       i, status;
  79.     long   l = 0;
  80.     char   bfn[NFILEN];
  81.  
  82.     i = 2;
  83.     fn[0] = '\0';
  84.     sz[0] = '\0';
  85.     cmnt[0] = '\0';
  86.  
  87.     while(i){
  88.  
  89.     if(i == 2){
  90.         wkeyhelp("GC00000T0000","Get Help,Cancel,To Files");
  91.         status = mlreply("File to attach: ", fn, NLINE, QFFILE);
  92.     }
  93.     else{
  94.         wkeyhelp("GC0000000000","Get Help,Cancel");
  95.         status = mlreply("Attachment comment: ", cmnt, NLINE, QNORML);
  96.     }
  97.  
  98.     switch(status){
  99.       case HELPCH:
  100.         if(i == 2)
  101.           emlwrite("No Attachment file help yet!");
  102.         else
  103.           emlwrite("No Attachment comment help yet!");
  104.  
  105. /* remove break and sleep when help text done to force redraw */     
  106.         sleep(3);
  107.         break;
  108.  
  109.       case (CTRL|'T'):
  110.         if(i != 2){
  111.         (*term.t_beep)();
  112.         break;
  113.         }
  114.  
  115.         *bfn = '\0';
  116.         if(*fn == '\0' || !isdir(fn, NULL))
  117.           strcpy(fn, gethomedir(NULL));
  118.  
  119.         if(FileBrowse(fn, bfn, sz) == 1){
  120.         strcat(fn, S_FILESEP);
  121.         strcat(fn, bfn);
  122.         i--;
  123.         }
  124.         else
  125.           *fn = '\0';
  126.  
  127.         refresh(FALSE, 1);
  128.         update();
  129.         break;
  130.  
  131.       case (CTRL|'L'):
  132.         refresh(FALSE, 1);
  133.         update();
  134.         continue;
  135.  
  136.       case ABORT:
  137.         emlwrite("\007Aborted");
  138.         return(0);
  139.       case TRUE:                /* some comment */
  140.       case FALSE:                /* No comment */
  141.         if(i-- == 2){
  142.         if((gmode&MDSCUR) && !compresspath("", fn, NLINE)){
  143.             emlwrite("\007Restricted mode allows attachments from home directory only", NULL);
  144.             return(0);
  145.         }
  146.  
  147.         fixpath(fn, NLINE);        /* names relative to ~ */
  148.         if((gmode&MDSCUR) && homeless(fn)){
  149.             emlwrite("\007Restricted mode allows attachments from home directory only", NULL);
  150.             return(0);
  151.         }
  152.  
  153.         if((status=fexist(fn, "r", &l)) != FIOSUC){ /* does file exist? */
  154.             fioperr(status, fn);
  155.             return(0);
  156.         }
  157.         strcpy(sz, prettysz(l));
  158.         }
  159.         else{
  160.         mlerase();
  161.         return(1);            /* mission accomplished! */
  162.         }
  163.  
  164.         break;
  165.       default:
  166.         break;
  167.     }
  168.     }
  169. }
  170.  
  171.  
  172.  
  173. /*
  174.  * SyncAttach - given a pointer to a linked list of attachment structures,
  175.  *              return with that structure sync'd with what's displayed.
  176.  *              delete any attachments in list of structs that's not on 
  177.  *              the display, and add any that aren't in list but on display.
  178.  */
  179. SyncAttach()
  180. {
  181.     int entry = ATTCHDR,            /* which set of header lines */
  182.         offset = 0,                /* the offset to begin       */
  183.         rv = 0,
  184.         ki = 0,                    /* number of known attmnts   */
  185.         bi = 0,                    /* build array index         */
  186.         na,                    /* old number of attachmnt   */
  187.         status, i, j, n;
  188.     char file[NLINE],                /* buffers to hold it all    */
  189.          size[32],
  190.          comment[1024];
  191.     struct hdr_line *lp;            /* current line in header    */
  192.     PATMT *tp, *knwn[MAXATCH], *bld[MAXATCH];
  193.  
  194.     if(Pmaster == NULL)
  195.       return(-1);
  196.  
  197.     for(i=0;i<MAXATCH;i++)            /* bug - ever pop this? */
  198.     knwn[i] = bld[i] = NULL;        /* zero out table */
  199.     
  200.     tp = Pmaster->attachments;
  201.     while(tp != NULL){                /* fill table of     */
  202.     knwn[ki++] = tp;            /* known attachments */
  203.     tp = tp->next;
  204.     }
  205.  
  206.     n = 0;
  207.     lp = headents[ATTCHDR].hd_text;
  208.     while(lp != NULL){
  209.     na = ++n;
  210.  
  211.     if(status = ParseAttach(&lp, &offset, file, size, comment, &na))
  212.         rv = (rv < 0) ? rv : status ;    /* remember worst case */
  213.  
  214.     if(*file == '\0'){
  215.         if(n != na && na > 0 && na <= ki && (knwn[na-1]->flags&A_FLIT)){
  216.         bld[bi++] = knwn[na-1];
  217.         knwn[na-1] = NULL;
  218.         }
  219.         continue;
  220.     }
  221.  
  222.     if((gmode&MDSCUR) && homeless(file))
  223.       /* no attachments outsize ~ in secure mode! */
  224.       continue;
  225.  
  226.     tp = NULL;
  227.     for(i=0;i < ki; i++){            /* already know about it? */
  228.         /*
  229.          * this is kind of gruesome. what we want to do is keep track
  230.          * of literal attachment entries because they may not be 
  231.          * actual files we can access or that the user readily 
  232.          * access
  233.          */
  234.         if(knwn[i] && 
  235.            ((!(knwn[i]->flags&A_FLIT) && !strcmp(file, knwn[i]->filename))
  236.            || ((knwn[i]->flags&A_FLIT) && i+1 == na))){
  237.         tp = knwn[i];
  238.         knwn[i] = NULL;            /* forget we know about it */
  239.  
  240.         if(status == -1)        /* ignore garbage! */
  241.           break;
  242.  
  243.         if((tp->flags&A_FLIT) && strcmp(file, tp->filename)){
  244.             rv = 1;
  245.             if((j=strlen(file)) > strlen(tp->filename)){
  246.             if((tp->filename = (char *)realloc(tp->filename,
  247.                             sizeof(char)*(j+1))) == NULL){
  248.                 emlwrite("\007Can't realloc space for filename");
  249.                 return(-1);
  250.             }
  251.             }
  252.  
  253.             strcpy(tp->filename, file);
  254.         }
  255.         else if(tp->size && strcmp(tp->size, size)){
  256.             rv = 1;
  257.             if((j=strlen(size)) > strlen(tp->size)){
  258.             if((tp->size=(char *)realloc(tp->size,
  259.                             sizeof(char)*(j+1))) == NULL){
  260.                 emlwrite("\007Can't realloc space for size");
  261.                 return(-1);
  262.             }
  263.             }
  264.  
  265.             strcpy(tp->size, size);
  266.         }
  267.  
  268.         if(strcmp(tp->description, comment)){    /* new comment */
  269.             rv = 1;
  270.             if((j=strlen(comment)) > strlen(tp->description)){
  271.             if((tp->description=(char *)realloc(tp->description,
  272.                         sizeof(char)*(j+1))) == NULL){
  273.                 emlwrite("\007Can't realloc description");
  274.                 return(-1);
  275.             }
  276.             }
  277.               
  278.             strcpy(tp->description, comment);
  279.         }
  280.         break;
  281.         }
  282.     }
  283.  
  284.     if(tp){
  285.         bld[bi++] = tp;
  286.     }
  287.     else{
  288.         if(file[0] != '['){
  289.         if((tp = NewAttach(file, size, comment)) == NULL)
  290.           return(-1);
  291.         bld[bi++] = tp;
  292.         }
  293.     }
  294.     }
  295.  
  296.     for(i=0; i < bi; i++)        /* link together newly built list */
  297.     bld[i]->next = bld[i+1];
  298.  
  299.     Pmaster->attachments = bld[0];
  300.  
  301.     for(i=0; i < ki; i++){        /* kill old/unused references */
  302.  
  303.     if(knwn[i]){
  304.         ZotAttach(knwn[i]);
  305.         free((char *) knwn[i]);
  306.     }
  307.     }
  308.  
  309.     return(rv);
  310. }
  311.  
  312.  
  313.  
  314.  
  315. /*
  316.  * ParseAttach - given a header line and an offset into it, return with 
  317.  *         the three given fields filled in.  Assumes the size of 
  318.  *         the buffers passed is large enough to hold what's there.
  319.  *         Always updates header fields that have changed or are 
  320.  *         fixed.  An error advances offset to next attachment.
  321.  *
  322.  *        returns: 1 if a field changed
  323.  *                       0 nothing changed
  324.  *                      -1 on error
  325.  */
  326. ParseAttach(lp, off, fn, sz, cmnt, no)
  327. struct hdr_line **lp;                /* current header line      */
  328. int  *off;                    /* offset into that line    */
  329. char *fn, *sz, *cmnt;                /* places to return fields  */
  330. int  *no;                    /* attachment number        */
  331. {
  332.     int  j, status,                /* various return codes     */
  333.          rv = 0,                /* return value             */
  334.          lbln  = 0;                /* label'd attachment        */
  335.     long l;                    /* attachment length        */
  336.     char c,
  337.         *p = s,
  338.         *lblsz = NULL,                /* label'd attchmnt's size  */
  339.          number[8];
  340.     register struct hdr_line  *lprev;
  341.     enum {                    /* parse levels             */
  342.     LWS,                    /* leading white space      */
  343.     NUMB,                    /* attachment number        */
  344.     WSN,                    /* white space after number */
  345.     TAG,                    /* attachments tag (fname)  */
  346.     WST,                    /* white space after tag    */
  347.     SIZE,                    /* attachments size         */
  348.     SWS,                    /* white space after size   */
  349.     COMMENT,                /* attachment comment       */
  350.     TG} level;                /* trailing garbage         */
  351.  
  352.     *fn = *sz = *cmnt = '\0';            /* initialize return strings */
  353.  
  354.     level = LWS;                /* start at beginning */
  355.     while(*lp != NULL){
  356.  
  357.     if((c=(*lp)->text[*off]) == '\0'){    /* end of display line */
  358.         lprev = *lp;
  359.         if((*lp = (*lp)->next) != NULL)
  360.           c = (*lp)->text[*off = 0];    /* reset offset */
  361.     }
  362.  
  363.     switch(level){
  364.       case LWS:                /* skip leading white space */
  365.         if(isspace(c) || c == '\0'){
  366.         break;
  367.         }
  368.         else if(c < '0' || c > '9'){    /* add a number */
  369.         sprintf(number, "%d. ", *no);
  370.         *no = 0;            /* no previous number! */
  371.         sinserts((*lp == NULL) ? &lprev->text[*off]
  372.                            : &(*lp)->text[*off],
  373.                  0, number, j=strlen(number));
  374.         *off += j - 1;
  375.         rv = 1;
  376.         level = TAG;            /* interpret the name */
  377.         break;
  378.         }
  379.         level = NUMB;
  380.       case NUMB:                /* attachment number */
  381.         if(c == '.'){            /* finished grabbing size */
  382.         /*
  383.          * replace number if it's not right
  384.          */
  385.         *p = '\0';
  386.         sprintf(number, "%d", *no);    /* record the current...  */
  387.         *no = atoi(s);            /* and the old place in list */
  388.         if(strcmp(number, s)){
  389.             if(p-s > *off){        /* where to begin replacemnt */
  390.             j = (p-s) - *off;
  391.             sinserts((*lp)->text, *off, "", 0);
  392.             sinserts(&lprev->text[strlen(lprev->text)-j], j, 
  393.                  number, strlen(number));
  394.             *off = 0;
  395.             }
  396.             else{
  397.             j = (*off) - (p-s);
  398.             sinserts((*lp == NULL) ? &lprev->text[j] 
  399.                                : &(*lp)->text[j], 
  400.                  p-s , number, strlen(number));
  401.             *off += strlen(number) - (p-s);
  402.             }
  403.             rv = 1;
  404.         }
  405.         p = s;
  406.         level = WSN;            /* what's next... */
  407.         }
  408.         else if(c < '0' || c > '9'){
  409.         *p = '\0';
  410.         emlwrite("\007Attchmnt: Number field missing '.': \"%s\"", s);
  411.         rv = -1;
  412.         }
  413.         else
  414.           *p++ = c;
  415.  
  416.         break;
  417.  
  418.       case WSN:                /* blast whitespace */
  419.         if(isspace(c) || c == '\0'){
  420.         break;
  421.         }
  422.         else if(c == '['){            /* labeled attachment */
  423.         lbln++;
  424.         }
  425.         else if(!fallowc(c)){
  426.         emlwrite("\007Attchmnt: '%c' not allowed in file name", c);
  427.         rv = -1;
  428.         level = TG;            /* eat rest of garbage */
  429.         break;
  430.         }
  431.         level = TAG;
  432.       case TAG:                /* get and check filename */
  433.                         /* or labeled attachment  */
  434.                         /* enclosed in []         */
  435.         if(c == '\0' || (!lbln && (isspace(c) || strchr(",(\"", c)))
  436.            || (lbln && c == ']')){
  437.         if(p != s){
  438.             *p = '\0';            /* got something */
  439.  
  440.             strcpy(fn, s);        /* store file name */
  441.             if(!lbln){            /* normal file attachment */
  442.             if((gmode&MDSCUR) && !compresspath("", fn, NLINE)){
  443.                 emlwrite("\007Restricted mode allows attachments from home directory only", NULL);
  444.                 rv = -1;
  445.                 level = TG;
  446.                 break;
  447.             }
  448.  
  449.             fixpath(fn, NLINE);
  450.             if((status=fexist(fn, "r", &l)) != FIOSUC){
  451.                 fioperr(status, fn);
  452.                 rv = -1;
  453.                 level = TG;        /* munch rest of garbage */
  454.                 break;
  455.             }
  456.  
  457.             if((gmode&MDSCUR) && homeless(fn)){
  458.                 emlwrite("\007Restricted mode allows attachments from home directory only", NULL);
  459.                 rv = -1;
  460.                 level = TG;
  461.                 break;
  462.             }
  463.  
  464.             if(strcmp(fn, s)){    /* fn changed: display it */
  465.                 if(*off >=  p - s){    /* room for it? */
  466.                 sinserts((*lp == NULL)? 
  467.                      &lprev->text[(*off)-(p-s)] :
  468.                      &(*lp)->text[(*off)-(p-s)],
  469.                      p-s, fn, j=strlen(fn));
  470.                 *off += j - (p - s);    /* advance offset */
  471.                 rv = 1;
  472.                 }
  473.                 else{
  474.                 emlwrite("\007Attchmnt: Problem displaying real file path");
  475.                 }
  476.             }
  477.             }
  478.             else{            /* labelled attachment! */
  479.             /*
  480.              * should explain about labelled attachments:
  481.              * these are attachments that came into the composer
  482.              * with meaningless file names (up to caller of 
  483.              * composer to decide), for example, attachments
  484.              * being forwarded from another message.  here, we
  485.              * just make sure the size stays what was passed
  486.              * to us.  The user is SOL if they change the label
  487.              * since, as it is now, after changed, it will
  488.              * just get dropped from the list of what gets 
  489.              * passed back to the caller.
  490.              */
  491.             PATMT *tp;
  492.  
  493.             if(c != ']'){        /* legit label? */
  494.                 emlwrite("\007Attchmnt: Expected ']' after \"%s\"",
  495.                      fn);
  496.                 rv = -1;
  497.                 level = TG;
  498.                 break;
  499.             }
  500.             strcat(fn, "]");
  501.  
  502.             /*
  503.              * This is kind of cheating since otherwise
  504.              * ParseAttach doesn't know about the attachment
  505.              * struct.  OK if filename's not found as it will
  506.              * get taken care of later...
  507.              */
  508.             tp = Pmaster->attachments; /* caller check Pmaster! */
  509.             j = 0;
  510.             while(tp != NULL){
  511.                 if(++j == *no){
  512.                 lblsz = tp->size;
  513.                 break;
  514.                 }
  515.                 tp = tp->next;
  516.             }
  517.  
  518.             if(tp == NULL){
  519.                 emlwrite("\007Attchmnt: Unknown reference: %s",fn);
  520.                 lblsz =  "XXX";
  521.             }
  522.             }
  523.             p = s;            /* reset p in s */
  524.             level = WST;
  525.         }
  526.  
  527.         if(!lbln && c == '(')        /* no space 'tween file, size*/
  528.           level = SIZE;
  529.         else if(c == '\0' || (!lbln && (c == ',' || c == '\"'))){
  530.             strcpy(sz, (lblsz) ? lblsz : prettysz(l));
  531.             sprintf(s, " (%s) %s", sz, (c == '\"') ? "" : "\"\"");
  532.             sinserts((*lp == NULL) ? &lprev->text[*off] 
  533.                                : &(*lp)->text[*off],
  534.                  0, s, j = strlen(s));
  535.             *off += j;
  536.             rv = 1;
  537.             level = (c == '\"') ? COMMENT : TG;/* cmnt or eat trash */
  538.         }
  539.         }
  540.         else if(!lbln && (!fallowc(c) || c == '[' || c == ']')){
  541.         emlwrite("\007Attchmnt: '%c' not allowed in file name", c);
  542.         rv = -1;            /* bad char in file name */
  543.         level = TG;            /* gobble garbage */
  544.         }
  545.         else
  546.           *p++ = c;                /* add char to name */
  547.  
  548.         break;
  549.  
  550.       case WST:                /* skip white space */
  551.         if(!isspace(c)){
  552.         /*
  553.          * whole attachment, comment or done! 
  554.          */
  555.         if(c == ',' || c == '\0' || c == '\"'){
  556.             strcpy(sz, (lblsz) ? lblsz : prettysz(l));
  557.             sprintf(s, " (%s) %s", sz, 
  558.                            (c == '\"') ? "" : "\"\"");
  559.             sinserts((*lp == NULL) ? &lprev->text[*off]
  560.                            : &(*lp)->text[*off],
  561.                  0, s, j = strlen(s));
  562.             *off += j;
  563.             rv = 1;
  564.             level = (c == '\"') ? COMMENT : TG;
  565.             lbln = 0;            /* reset flag */
  566.         }
  567.         else if(c == '('){        /* get the size */
  568.             level = SIZE;
  569.         }
  570.         else{
  571.             emlwrite("\007Attchmnt: Expected '(' or '\"' after %s",fn);
  572.             rv = -1;            /* bag it all */
  573.             level = TG;
  574.         }
  575.         }
  576.         break;
  577.  
  578.       case SIZE:                /* check size */
  579.         if(c == ')'){            /* finished grabbing size */
  580.         *p = '\0';
  581.         /*
  582.          * replace sizes if they don't match!
  583.          */
  584.         strcpy(sz, s);
  585.         if(strcmp(sz, (lblsz) ? lblsz : prettysz(l))){
  586.             strcpy(sz, (lblsz) ? lblsz : prettysz(l));
  587.             if(p-s > *off){        /* where to begin replacemnt */
  588.             j = (p-s) - *off;
  589.             sinserts((*lp)->text, *off, "", 0);
  590.             sinserts(&lprev->text[strlen(lprev->text)-j], j, 
  591.                  sz, strlen(sz));
  592.             *off = 0;
  593.             }
  594.             else{
  595.             j = (*off) - (p-s);
  596.             sinserts((*lp == NULL) ? &lprev->text[j] 
  597.                                : &(*lp)->text[j], 
  598.                  p-s , sz, strlen(sz));
  599.             *off += strlen(sz) - (p-s);
  600.             }
  601.             rv = 1;
  602.         }
  603.         p = s;
  604.         level = SWS;            /* what's next... */
  605.         }
  606.         else if(c == '\0' || c == ','){
  607.         *p = '\0';
  608.         emlwrite("\007Attchmnt: Size field missing ')': \"%s\"", s);
  609.         rv = -1;
  610.         level = TG;
  611.         }
  612.         else
  613.           *p++ = c;
  614.  
  615.         break;
  616.  
  617.       case SWS:                /* skip white space */
  618.         if(!isspace(c)){
  619.         if(c == ','){            /* no description */
  620.             level = TG;            /* munch rest of garbage */
  621.             lbln = 0;            /* reset flag */
  622.         }
  623.         else if(c != '\"' && c != '\0'){
  624.             emlwrite("\007Attchmnt: Malformed comment, quotes required");
  625.             rv = -1;
  626.             level = TG;
  627.         }
  628.         else
  629.           level = COMMENT;
  630.         }
  631.         break;
  632.  
  633.       case COMMENT:                /* slurp up comment */
  634.         if(c == '\"' || c == '\0'){        /* got comment */
  635.         *p = '\0';            /* cap it off */
  636.         p = s;                /* reset p */
  637.         strcpy(cmnt,s);            /* copy the comment  */
  638.         if(c == '\0'){
  639.             emlwrite("\007Attchmnt: Closing quote required at end of comment");
  640.             rv = -1;
  641.         }
  642.         level = TG;            /* prepare for next one */
  643.         lbln = 0;            /* reset flag */
  644.         }
  645.         else
  646.           *p++ = c;
  647.  
  648.         break;
  649.  
  650.       case TG:                /* get comma or final EOL */
  651.         if(!isspace(c)){
  652.         if(c != ',' && c != '\0'){
  653.             if(rv != -1)
  654.               emlwrite("\007Attchmnt: Comma must separate attachments");
  655.             rv = -1;
  656.         }
  657.         }
  658.         break;
  659.  
  660.       default:                /* something's very wrong */
  661.         emlwrite("\007Attchmnt: Weirdness in ParseAttach");
  662.         return(-1);                /* just give up */
  663.     }
  664.  
  665.     if(c == '\0')                /* we're done */
  666.       break;
  667.  
  668.     (*off)++;
  669.  
  670.     /*
  671.      * not in comment or label name? done. 
  672.      */
  673.     if(c == ',' && (level != COMMENT && !lbln))
  674.       break;                /* put offset past ',' */
  675.     }
  676.  
  677.     return(rv);
  678. }
  679.  
  680.  
  681.  
  682. /*
  683.  * NewAttach - given a filename (assumed to accessible) and comment, creat
  684.  */
  685. PATMT *NewAttach(f, l, c)
  686. char *f;
  687. long l;
  688. char *c;
  689. {
  690.     char   *cp;
  691.     PATMT  *tp;
  692.  
  693.     if((tp=(PATMT *)malloc(sizeof(PATMT))) == NULL){
  694.     emlwrite("No memory to add attachment");
  695.     return(NULL);
  696.     }
  697.     else{
  698.     tp->filename = tp->description = NULL;
  699.     tp->size = tp->id = NULL;
  700.     tp->next = NULL;
  701.     }
  702.  
  703.     /* file and size malloc */
  704.     if((tp->filename = (char *)malloc(strlen(f)+1)) == NULL){
  705.     emlwrite("Can't malloc name for attachment");
  706.     free((char *) tp);
  707.     return(NULL);
  708.     }
  709.     strcpy(tp->filename, f);
  710.  
  711.     if(l > -1){
  712.     strcpy(s, prettysz(l));
  713.     if((tp->size = (char *)malloc(sizeof(char)*(strlen(s)+1))) == NULL){
  714.         emlwrite("Can't malloc size for attachment");
  715.         free((char *) tp->filename);
  716.         free((char *) tp);
  717.         return(NULL);
  718.     }
  719.     else
  720.       strcpy(tp->size, s);
  721.     }
  722.  
  723.     /* description malloc */
  724.     if((tp->description = (char *)malloc(strlen(c)+1)) == NULL){
  725.     emlwrite("Can't malloc description for attachment");
  726.     free((char *) tp->size);
  727.     free((char *) tp->filename);
  728.     free((char *) tp);
  729.     return(NULL);
  730.     }
  731.     strcpy(tp->description, c);
  732.  
  733.     return(tp);
  734. }
  735.  
  736.  
  737. void ZotAttach(p)
  738. PATMT *p;
  739. {
  740.     if(!p)
  741.       return;
  742.     if(p->description)
  743.       free((char *)p->description);
  744.     if(p->filename)
  745.       free((char *)p->filename);
  746.     if(p->size)
  747.       free((char *)p->size);
  748.     if(p->id)
  749.       free((char *)p->id);
  750.     p->next = NULL;
  751. }
  752. #endif    /* ATTACHMENTS */
  753.  
  754.  
  755. /*
  756.  * intag - return TRUE if i is in a column that makes up an
  757.  *         attachment line number
  758.  */
  759. intag(s, i)
  760. char *s;
  761. int   i;
  762. {
  763.     char *p = s;
  764.     int n = 0;
  765.  
  766.     while(*p != '\0' && (p-s) < 5){        /* is there a tag? it */
  767.     if(n && *p == '.')            /* can't be more than 4 */
  768.       return(i <= p-s);                /* chars long! */
  769.  
  770.     if(*p < '0' || *p > '9')
  771.       break;
  772.     else
  773.       n = (n * 10) + (*p - '0');
  774.  
  775.     p++;
  776.     }
  777.  
  778.     return(FALSE);
  779. }
  780.  
  781.  
  782. /*
  783.  * prettysz - return pointer to string containing nice
  784.  */
  785. char *prettysz(l)
  786. long l;
  787. {
  788.     static char b[32];
  789.  
  790.     if(l < 1000)
  791.       sprintf(b, "%d  B", l);            /* xxx B */
  792.     else if(l < 10000)
  793.       sprintf(b, "%1.1f KB", (float)l/1000);    /* x.x KB */
  794.     else if(l < 1000000)
  795.       sprintf(b, "%d KB", l/1000);        /* xxx KB */
  796.     else if(l < 10000000)
  797.       sprintf(b, "%1.1f MB", (float)l/1000000); /* x.x MB */
  798.     else
  799.       sprintf(b, "%d MB", l/1000000);        /* xxx MB */
  800.     return(b);
  801. }
  802.  
  803.  
  804. /*
  805.  * sinserts - s insert into another string
  806.  */
  807. sinserts(ds, dl, ss, sl)
  808. char *ds, *ss;                    /* dest. and source strings */
  809. int  dl, sl;                    /* their lengths */
  810. {
  811.     char *dp, *edp;                /* pointers into dest. */
  812.     int  j;                    /* jump difference */
  813.  
  814.     if(sl >= dl){                /* source bigger than dest. */
  815.     dp = ds + dl;                /* shift dest. to make room */
  816.     if((edp = strchr(dp, '\0')) != NULL){
  817.         j = sl - dl;
  818.  
  819.         for( ;edp >= dp; edp--)
  820.           edp[j] = *edp;
  821.  
  822.         while(sl--)
  823.            *ds++ = *ss++;
  824.     }
  825.     else
  826.       emlwrite("\007No end of line???");    /* can this happen? */
  827.     }
  828.     else{                    /* dest is longer, shrink it */
  829.     j = dl - sl;                /* difference in lengths */
  830.  
  831.     while(sl--)                /* copy ss onto ds */
  832.       *ds++ = *ss++;
  833.  
  834.     if(strlen(ds) > j){            /* shuffle the rest left */
  835.         do
  836.           *ds = ds[j];
  837.         while(*ds++ != '\0');
  838.     }
  839.     else
  840.       *ds = '\0';
  841.     }
  842. }
  843.